package com.supcon.common;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.supcon.util.FriendlyException;
import com.supcon.util.ResultInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author BeautifulHao
 * @description 通用异常处理
 * @create 2019-04-26 10:46
 **/
@Component
@Slf4j
public class ExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {

        if(isAjaxRequest(httpServletRequest)) {
            httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setHeader("Cache-Control", "no-cache, must-revalidate");

            ResultInfo<Map<String,Object>> resultInfo = new ResultInfo<>(false,new HashMap<>(),e.getMessage());

            if(e instanceof FriendlyException){
                resolverFriendlyException(e,resultInfo);
            }
            else if(e instanceof BindException){
                resolverBindException(e,resultInfo);
            }
            else {
                resolverOtherException(e,resultInfo);
            }

            try {
                httpServletResponse.getWriter().write(new ObjectMapper().writeValueAsString(resultInfo));
            } catch (IOException ex) {
                log.error(ex.getMessage());
            }

            return new ModelAndView();
        }
        else {
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.getModel().put("info",e.getMessage());
            modelAndView.setViewName("/base/error");
            return modelAndView;
        }
    }

    /*
     * 处理业务层异常
     */
    private void resolverFriendlyException(Exception ex, ResultInfo<Map<String,Object>> result) {
        FriendlyException businessException = (FriendlyException) ex;
        result.getResults().put("msg",businessException.getMsg());
    }

    /*
     * 处理参数绑定异常
     */
    private void resolverBindException(Exception ex, ResultInfo<Map<String,Object>> result) {
        BindException be = (BindException) ex;
        List<FieldError> errorList = be.getBindingResult().getFieldErrors();
        for (FieldError error : errorList) {
            result.getResults().put(error.getField(),error.getDefaultMessage());
        }
    }

    /*
     * 处理其他异常
     */
    private void resolverOtherException(Exception ex, ResultInfo<Map<String,Object>> result) {
        result.getResults().put("sys",ex.getMessage());
        result.setMessage("服务器端发生异常，请联系管理员！");
    }


    private boolean isAjaxRequest(HttpServletRequest request) {
        String requestedWith = request.getHeader("X-Requested-With");
        if (requestedWith != null && requestedWith.equalsIgnoreCase("XMLHttpRequest")) {
            return true;
        } else {
            return false;
        }
    }
}
